package com.zxjbyte.yiyi.framework.redis.config;

import com.zxjbyte.yiyi.framework.redis.listener.AbstractMessageListener;
import com.zxjbyte.yiyi.framework.redis.lock.RLockTemplate;
import com.zxjbyte.yiyi.framework.redis.lock.aspect.RLockAspect;
import com.zxjbyte.yiyi.framework.redis.lock.executor.FairRLockExecutor;
import com.zxjbyte.yiyi.framework.redis.lock.executor.IRLockExecutor;
import com.zxjbyte.yiyi.framework.redis.lock.executor.ReentrantRLockExecutor;
import com.zxjbyte.yiyi.framework.redis.manager.RedisDao;
import com.zxjbyte.yiyi.framework.redis.serializer.RedisKeySerializer;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.RedisSerializer;

import javax.annotation.Resource;
import java.util.List;

/**
 * redis自动配置类
 * @Author zhangxingjia
 * @Date 2023/2/28 11:32
 * @Version: 1.0
 */
@AutoConfiguration
@EnableConfigurationProperties(RedisProperties.class)
public class YiyiRedisAutoConfiguration {

    @Resource
    private RedisProperties properties;

    @Bean(name = "redisTemplate")
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // key 序列化
        RedisKeySerializer keySerializer = new RedisKeySerializer();
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setHashKeySerializer(keySerializer);
        // value 序列化
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    @Bean
    public RedisDao redisDao(RedisTemplate<String, Object> redisTemplate, StringRedisTemplate stringRedisTemplate){
        return new RedisDao(redisTemplate, stringRedisTemplate);
    }

    // ============================Pub/Sub===========================

    @Bean(initMethod = "start", destroyMethod = "stop")
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory, List<AbstractMessageListener<?>> listenerList){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        listenerList.forEach(listener -> {
            container.addMessageListener(listener, ChannelTopic.of(listener.getChannel()));
        });
        return container;
    }

    // ============================分布式锁===========================

    @Bean
    @ConditionalOnMissingBean
    public ReentrantRLockExecutor reentrantRLockExecutor(RedissonClient redissonClient){
        return new ReentrantRLockExecutor(redissonClient);
    }

    @Bean
    @ConditionalOnMissingBean
    public FairRLockExecutor fairRLockExecutor(RedissonClient redissonClient){
        return new FairRLockExecutor(redissonClient);
    }

    @SuppressWarnings("rawtypes")
    @Bean
    public RLockTemplate rLockTemplate(List<IRLockExecutor> executors){
        return new RLockTemplate(properties, executors);
    }

    @Bean
    public RLockAspect rLockAspect(RLockTemplate rLockTemplate){
        return new RLockAspect(rLockTemplate);
    }
}
